<template>
  <div class="text-expand" ref="textContainer">
    <div ref="textContent" class="text-content" :class="{ 'text-collapsed': !expanded && hasOverflow }" :style="!expanded && hasOverflow ? {
      '-webkit-line-clamp': maxLines,
      'display': '-webkit-box',
      '-webkit-box-orient': 'vertical',
      'overflow': 'hidden'
    } : {}">
      <slot></slot>
      <span v-if="hasOverflow" class="expand-link-container">
        <a class="expand-link" href="javascript:void(0)" @click.stop="toggleExpand">
          {{ expanded ? '收起' : '展开' }}
        </a>
      </span>
    </div>
  </div>
</template>
<script>
export default {
  name: 'TextExpand',
  props: {
    // 最大显示行数
    maxLines: {
      type: Number,
      default: 3
    }
  },
  data() {
    return {
      expanded: false,
      hasOverflow: false,
      observer: null
    }
  },
  mounted() {
    // 使用 ResizeObserver 监听元素尺寸变化
    this.observer = new ResizeObserver(() => {
      this.checkOverflow();
    });

    if (this.$refs.textContainer) {
      this.observer.observe(this.$refs.textContainer);
    }

    // 确保文本内容已渲染后再检查
    setTimeout(() => {
      this.checkOverflow();
    }, 100);
  },
  beforeUnmount() {
    // 清理 ResizeObserver
    if (this.observer) {
      this.observer.disconnect();
    }
  },
  watch: {
    // 监听文本变化重新检查
    text() {
      this.$nextTick(() => {
        setTimeout(() => {
          this.checkOverflow();
        }, 100);
      });
    }
  },
  methods: {
    toggleExpand() {
      this.expanded = !this.expanded;
    },
    checkOverflow() {
      const textEl = this.$refs.textContent;
      const containerEl = this.$refs.textContainer;

      if (!textEl || !containerEl) return;

      // 保存原始状态
      const originalOverflow = textEl.style.overflow;
      const originalWebkitLineClamp = textEl.style.webkitLineClamp;
      const originalDisplay = textEl.style.display;
      const originalWebkitBoxOrient = textEl.style.webkitBoxOrient;

      // 清除限制，让文本完全展开
      textEl.style.overflow = 'visible';
      textEl.style.webkitLineClamp = 'none';
      textEl.style.display = 'block';
      textEl.style.webkitBoxOrient = 'horizontal';

      // 获取内容高度和行高
      const contentHeight = textEl.scrollHeight;
      const computedStyle = window.getComputedStyle(textEl);
      const lineHeight = parseFloat(computedStyle.lineHeight) ||
        parseFloat(computedStyle.fontSize) * 1.2;

      // 计算最大允许高度
      const maxHeight = lineHeight * this.maxLines + 4;

      // 判断是否溢出
      this.hasOverflow = contentHeight > maxHeight;

      // console.log("hasOverflow=%s,lineHeight=%d,contentHeight=%d,maxHeight=%d,%s", this.hasOverflow, lineHeight, contentHeight, maxHeight, this.text)

      // 恢复原始状态(仅当未展开时)
      if (!this.expanded) {
        textEl.style.overflow = originalOverflow;
        textEl.style.webkitLineClamp = originalWebkitLineClamp;
        textEl.style.display = originalDisplay;
        textEl.style.webkitBoxOrient = originalWebkitBoxOrient;
      }
    }
  },
}
</script>

<style scoped>
.text-expand {
  position: relative;
  width: 100%;
}

.text-content {
  word-break: break-all;
  word-wrap: break-word;
  line-height: 1.5;
  position: relative;
}

.text-collapsed {
  position: relative;
  padding-right: 1em;
  /* 为展开按钮预留空间 */
}

.expand-link-container {
  display: inline;
  white-space: nowrap;
}

.expand-link {
  color: #409eff;
  cursor: pointer;
  text-decoration: none;
  padding-left: 4px;
}

.text-collapsed .expand-link-container {
  position: absolute;
  right: 12px;
  bottom: 0;
  background: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1) 60%);
  padding-left: 8px;
}

.expand-link:hover {
  color: #66b1ff;
}
</style>